home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / db / esm-3.1 / esm-3 / usr / local / sm / src / client / lm / lock.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-05  |  8.1 KB  |  353 lines

  1. /*
  2.  *   $RCSfile: lock.c,v $  
  3.  *   $Revision: 1.1.1.1 $  
  4.  *   $Date: 1996/05/04 21:55:26 $      
  5.  */ 
  6. /**********************************************************************
  7. * EXODUS Database Toolkit Software
  8. * Copyright (c) 1991 Computer Sciences Department, University of
  9. *                    Wisconsin -- Madison
  10. * All Rights Reserved.
  11. *
  12. * Permission to use, copy, modify and distribute this software and its
  13. * documentation is hereby granted, provided that both the copyright
  14. * notice and this permission notice appear in all copies of the
  15. * software, derivative works or modified versions, and any portions
  16. * thereof, and that both notices appear in supporting documentation.
  17. *
  18. * THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY OF WISCONSIN --
  19. * MADISON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.  
  20. * THE DEPARTMENT DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
  21. * WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  22. *
  23. * The EXODUS Project Group requests users of this software to return 
  24. * any improvements or extensions that they make to:
  25. *
  26. *   EXODUS Project Group 
  27. *     c/o David J. DeWitt and Michael J. Carey
  28. *   Computer Sciences Department
  29. *   University of Wisconsin -- Madison
  30. *   Madison, WI 53706
  31. *
  32. *     or exodus@cs.wisc.edu
  33. *
  34. * In addition, the EXODUS Project Group requests that users grant the 
  35. * Computer Sciences Department rights to redistribute these changes.
  36. **********************************************************************/
  37. #include "sysdefs.h"
  38. #include "ess.h"
  39. #include "checking.h"
  40. #include "trace.h"
  41. #include "error.h"
  42. #include "io.h"
  43. #include "list.h"
  44. #include "object.h"
  45. #include "tid.h"
  46. #include "lock.h"
  47. #include "page.h"
  48. #include "bf.h"
  49. #include "lm.h"
  50. #include "chunk.h"
  51. #include "bf_extfuncs.h"
  52. #include "bf_globals.h"
  53. #include "serverinfo.h"
  54. #include "sm_state.h"
  55. #include "trans.h"
  56. #include "trans_globals.h"
  57. #include "cc_macro.h"
  58. #include "lm_extfuncs.h"
  59. #include "lm_intfuncs.h"
  60. #include "lock_globals.h"
  61. #include "sm_globals.h"
  62.  
  63. #ifdef LM_TRACE
  64. #undef LM_TRACE
  65. #define LM_TRACE(x)    printf x
  66. #else
  67. #define LM_TRACE(x)
  68. #endif
  69.  
  70.  
  71.  
  72. static int releaseQueueLen = 0;
  73. static void LM_UnlockPid(PID* pid, PAGEHASH* pageHash);
  74.  
  75. typedef struct {
  76.         PID            pid;
  77.         PAGEHASH*    pageHash;
  78.         LOCKMODE    mode;
  79.         int             next;
  80.         } PIDLock;
  81.  
  82. static PIDLock  lockPool[LM_RELEASELIMIT+1];
  83.  
  84. static int freeList = 0;
  85. static int releaseQueue = -1;
  86. static int initialized = FALSE;
  87.  
  88. static int lockCaching = 1;
  89.  
  90.  
  91. static void LM_Initialize()
  92. {
  93.     int i;
  94.     for (i = 0; i < 8; i++)
  95.         lockPool[i].next = i+1;
  96.     lockPool[7].next = -1;
  97.  
  98.     freeList = 0;
  99.     initialized = TRUE;
  100. }
  101.  
  102.  
  103.  
  104. void LM_PrintQueue()
  105. {
  106.     register int p = releaseQueue;
  107.     printf("Queue = ");
  108.     for ( ; p >= 0; p = lockPool[p].next)  {
  109.         printf(" [%d]", lockPool[p].pid.page);
  110.         }
  111.     printf("\n");
  112. }
  113.  
  114.  
  115. lm_LockFile(FID* fid, LOCKMODE lockMode)
  116. {
  117.     if (rpc_LockFile(fid, &lockMode))    return esmFAILURE;
  118.     
  119.     return esmNOERROR;
  120. }
  121.  
  122.  
  123.  
  124. lm_LockPage(const PID* pid, PAGEHASH* pageHash, LOCKMODE lockMode, FID* fid)
  125. {
  126.     if ( ! initialized) LM_Initialize();
  127.     
  128.     LM_TRACE(("Locking page %d", pid->page));
  129.  
  130.     /*
  131.      *    See if page lock is cached in releaseQueue
  132.      */
  133.     if (lockCaching)  {
  134.         register int     p = releaseQueue;
  135.         register int*     pp = &releaseQueue;
  136.         for ( ; p>=0 &&  ! PIDEQ(lockPool[p].pid, *pid); 
  137.                             pp = & lockPool[p].next, p = lockPool[p].next) ;
  138.  
  139.         if (p < 0)  {
  140.             LM_TRACE(("(miss) \n"));
  141.             }
  142.         else {
  143.             /*
  144.              *     Page lock is in releaseQueue --- see if need to upgrade lock
  145.              */
  146.             LOCKMODE suprMode = LM_Supremum[lockPool[p].mode][lockMode];
  147.             if (suprMode != lockPool[p].mode)  {
  148.                 /* call server to upgrade lock */
  149.                 if (rpc_LockPage(pid, PPAGE_TYPE(pageHash), &suprMode, fid))
  150.                     return esmFAILURE;
  151.                 }
  152.                 lockPool[p].mode = suprMode;
  153.  
  154.                 /*
  155.                  *    Unlock node from releaseQueue ---
  156.                  *    i.e. take out from cache
  157.                  */
  158.                 SET_PAGEHASHLOCK(pageHash, suprMode);
  159.                 *pp = lockPool[p].next;
  160.                 lockPool[p].next = freeList;
  161.                 freeList = p;
  162.                 releaseQueueLen--;
  163.                 
  164.                 LM_TRACE(("(hit) \n"));
  165.  
  166.                 return esmNOERROR;
  167.             }
  168.         }
  169.     
  170.     /*
  171.      *     Call server to lock page
  172.      */
  173.     if (rpc_LockPage(pid, PPAGE_TYPE(pageHash), &lockMode, fid))
  174.         return esmFAILURE;
  175.     pageHash->releaseCnt = 0;
  176.     pageHash->releaseLimit = LM_RELEASELIMIT;
  177.  
  178.     SET_PAGEHASHLOCK(pageHash, lockMode);
  179.  
  180.     return esmNOERROR;
  181. }
  182.  
  183.  
  184.  
  185. void lm_UnlockPage(PID* pid, PAGEHASH* pageHash)
  186. {
  187.     register int p;
  188.     LOCKMODE mode;
  189.  
  190.     if ( ! lockCaching)  {
  191.         LM_UnlockPid(pid, pageHash);
  192.         return; 
  193.         }
  194.  
  195.     LM_TRACE(("Unlocking page %d\n", pid->page));
  196.  
  197.     if ( ! initialized)        LM_Initialize();
  198.  
  199.     if ( ! (pageHash->flags & UNLOCKABLE_PAGE))  {
  200.         printf("Trying to release non-unlockable locks\n");
  201.         exit(-1);
  202.         }
  203.  
  204. #ifdef DEBUG
  205.     for (p = releaseQueue; p >= 0; p = lockPool[p].next)  {
  206.         if (PIDEQ(lockPool[p].pid, *pid))  {
  207.             printf("Page %d was unlocked\n", pid->page);
  208.             LM_PrintQueue();
  209.             exit(-1);
  210.             }
  211.         }
  212. #endif
  213.     
  214.     GET_PAGEHASHLOCK(pageHash, mode);
  215.     SET_PAGEHASHLOCK(pageHash, NL);
  216.  
  217.     if (++pageHash->releaseCnt >= pageHash->releaseLimit)   {
  218.         /*
  219.          *     Reached pageHash->releaseLimit of this lock. 
  220.          */
  221.         int serverReleaseLimit = 0;
  222.         if (rpc_CheckPage(pid, pageHash->releaseLimit, &serverReleaseLimit))
  223.             return;
  224.         if (serverReleaseLimit == 0)  {
  225.             /*
  226.              *    Another transaction is waiting
  227.              */
  228.             LM_TRACE(("Another xact is waiting ... unlocking page %d\n", 
  229.                                                             pid->page));
  230.             LM_UnlockPid(pid, pageHash);
  231.             return;
  232.             }
  233.         LM_TRACE(("ReleaseLimit for page %d changed to %d\n", 
  234.                             pid->page, serverReleaseLimit));
  235.         pageHash->releaseLimit = serverReleaseLimit;
  236.         pageHash->releaseCnt = 0;
  237.         }
  238.  
  239.     /* add lock to rear of release queue */
  240.     p = freeList;                    /* allocate a node */
  241.     SM_ASSERT(LEVEL_3, (p >= 0 && p < 8));
  242.     freeList = lockPool[p].next;
  243.     SM_ASSERT(LEVEL_3, (freeList == -1 || (freeList >= 0 && freeList < 8)));
  244.  
  245.     lockPool[p].pid = *pid;
  246.     lockPool[p].pageHash = pageHash;
  247.     lockPool[p].mode = mode;
  248.     lockPool[p].next = releaseQueue;
  249.     releaseQueue = p;
  250.  
  251.     if (releaseQueueLen++ >= LM_RELEASELIMIT)  {
  252.         int* pp = 0;
  253.         releaseQueueLen = LM_RELEASELIMIT;
  254.         LM_TRACE(("releaseQueueLen = %d, Limit = %d\n", releaseQueueLen, 
  255.                                                         LM_RELEASELIMIT));
  256.  
  257.         for ( ; lockPool[p].next >= 0; 
  258.                     pp = & lockPool[p].next, p = lockPool[p].next) ;
  259.         *pp = -1;
  260.         LM_UnlockPid(& lockPool[p].pid, lockPool[p].pageHash);
  261.  
  262.         lockPool[p].next = freeList;
  263.         freeList = p;
  264.         }
  265. }
  266.  
  267.  
  268.  
  269.  
  270. void lm_InvalidateAllLocks()
  271. {
  272.     PID pids[sizeof(lockPool) / sizeof(lockPool[0])];
  273.     int p;
  274.     int cnt;
  275.  
  276.     LM_TRACE(("Releasing all locks\n"));
  277.  
  278.     for (p = releaseQueue, cnt = 0;  p >= 0; p = lockPool[p].next)  {
  279.         pids[cnt++] = lockPool[p].pid;
  280.         }
  281.  
  282.     for (p = cnt - 1; p >= 0; p--)  {
  283.         LM_TRACE(("Releasing lock on page page %d \n", pids[p].page));
  284.         lm_InvalidateLock(& pids[p] );
  285.         }
  286. }
  287.  
  288. lm_IsLockCached(const PID* pid)
  289. {
  290.     for (register p = releaseQueue; 
  291.             p >= 0 && ! PIDEQ(lockPool[p].pid, *pid); p = lockPool[p].next);
  292.  
  293.     return p >= 0;
  294. }
  295.  
  296. void lm_ClearLockCache()
  297. {
  298.     int pp;
  299.     for (register p = releaseQueue; p >= 0; p = pp)  {
  300.         pp = lockPool[p].next;
  301.         lockPool[p].next = freeList;
  302.         freeList = p;
  303.     }
  304.     releaseQueueLen = 0;
  305.     releaseQueue = -1;
  306. }
  307.  
  308.  
  309. void lm_InvalidateLock(const PID* pid)
  310. {
  311.     register int p = releaseQueue;
  312.     register int* pp = &releaseQueue;
  313.  
  314.     for ( ; p >= 0 && ! PIDEQ(lockPool[p].pid, *pid); 
  315.                 pp = & lockPool[p].next, p = lockPool[p].next)  ;
  316.     if (p >= 0) {
  317.         *pp = lockPool[p].next;
  318.         releaseQueueLen--;
  319.         lockPool[p].next = freeList;
  320.         freeList = p;
  321.         bf_RemoveFromBufGroups(lockPool[p].pageHash);
  322.         LM_UnlockPid(& lockPool[p].pid, lockPool[p].pageHash);
  323.         }
  324. }
  325.  
  326.  
  327. static void LM_UnlockPid(PID* pid, PAGEHASH* pageHash)
  328. {
  329.     /*
  330.      * Invalidate the local copy of the page, flushing it to
  331.      * the server if the page is dirty.
  332.      *
  333.      * Do not leave the page in the hash table for possible reclaims
  334.      *  (for now, reclaims are done only on SLOTTED pages).
  335.      * (remove == TRUE, forceToServer == TRUE)
  336.      *
  337.      * NB: we might have been called from bf_InvalidatePage(), but
  338.      * if so, it will have removed the page hash from the hash table
  339.      * so the recursive call will simply return.
  340.      */
  341.     bf_RemoveFromBufGroups(pageHash);
  342.     bf_InvalidatePage(pageHash, TRUE, TRUE);
  343.  
  344.     /*
  345.      * release lock on the server
  346.      */
  347.     LM_TRACE(("Unlocking page %d at server\n", pid->page));
  348.     
  349.     if (rpc_UnlockPage(pid))  {
  350.         SM_ERROR(TYPE_WARNING, sm_errno);
  351.     }
  352. }
  353.